# 可执行程序名 : uppercaser
# 版本 : 1.0
# 创建日期 : 2019-04-24 16:24
# 最后修改日期 ： 2019-04-24
# 作者 ： Jeff Duntemann
# 描述 ：一个为Linux编写的简单汇编程序，使用 gas
#       展示了简单的文本文件输入/输出(通过重定向)
#       为了实现从输入文件读取到一块缓冲区，在缓冲区中将小写字符转换为大写
#       并将修改过的缓冲区写入到一个输出文件。
#以这种方式来运行它：
#        uppercaser > (output file) < (input file)

#通过这些命令来生成它：
#         as --gstabs -o uppercaser.o 02uppercaser.s
#         ld -o uppercaser uppercaser.o
.code32
#.SECTION .bss                           # 包含未初始化数据的段

.SECTION .data                          # 包含已初始化数据的段
    Buff:
             .string "0000"
.SECTION  .text                         # 包含代码的段

.global _start                          # 连接器需要这个来找到入口点!

_start:
   # nop                                 # 无操作指令 让gdb感到非常高兴

         # 从标准输入中读入满满一缓冲区文本:
    read:
        movl $0x3, %eax                     # 指定系统调用(sys_read)
        movl $0x0, %ebx                     # 指定文件描述符(0: 标准输入)
        movl $Buff, %ecx                    # 指定要读入的缓冲区的地址
        movl $0x4, %edx                     # 一次循环要读入的字节数
        int $0x80                           # 执行系统调用,调用sys_read来填充缓冲区

        movl %eax, %esi                     # 将系统调用的返回值(eax)复制到esi中
        cmpl $0,%eax                        # 如果eax==0,则sys_read到了标准  输入的结尾
        je Done                             # 如果(与0比较)相等就跳转

       # 设置寄存器，用于处理缓冲区这个步骤：
       movl %esi, %ecx                     # 将读入的字节数放入到ecx中
       movl $0x34, %eax                    # 将缓冲区地址放入到ebp中
       dec %eax                            # 将地址减1

       # 详细检查缓冲区，并将小写字符转换成大些字符
   Scan:
       cmpb $0x61,(%ebp,%ecx)              # 比较'a'与输入字符的大小 (第二个操作数减第一个操作数)（从右往左取）(将ebp加上ecx后取该缓冲区地址中的内容)
       jb Next                             # 比 'a' 小，不是小写字母 则跳转
       cmpb $0x7A,(%ebp,%ecx)              # 比较 'z' 与输入字符的大小
       ja Next                             # 比'z'大 也不是小写字母 跳转

       # 是小写字母则转大些
       subb $0x20, (%ebp,%ecx)             # 将该地址对应的小写字母减32转大写

   Next:
       decl %ecx                           # 字节计数减1
       jnz Scan                            # 如果还有字符(ecx不为0)，继续取下一个字符

   Write:
       movl $0x4, %eax                     # 指定系统调用(sys_write)
       movl $0x1, %ebx                     # 文件描述符（1：标转输出）
       movl $Buff, %ecx                    # 缓冲区的地址
       movl %edx, %esi                     # 设置字节长度
       int $0x80                            # 执行系统调用(sys_write)
       jmp read                            # 再次读取

Done:
    movl $0x1, %eax                     # 指定系统调用(sys_exit)
    movl $0x0, %ebx                     # 退出代码（参数）
    int $0x80                           # 执行
